package lecture;

import menus.LectureMenuItem;
import menus.MenuCategory;
import java.io.Serializable;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import user.Role;
import score.Score;
import task.ExerciseSheet;
import task.TaskCategory;
import downloads.DownloadCategory;
import news.News;
import groups.Wish;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import user.User;
import groups.MeetingDate;
import java.io.File;
import javax.persistence.CascadeType;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import mail.Mail;
import staticPage.StaticPage;
import handingIn.HandingIn;
import handingIn.HandingInData;
import hibernate.HibernateUtil;
import javax.persistence.FetchType;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import score.ScoreData;

/**
 *
 * @author Thorsten Ludwig
 */
@Entity
public class Lecture implements Serializable {

    @OneToOne(cascade=CascadeType.ALL)
    private LectureInformation info;
    
    /**
     * 
     */
    private HashMap<String,Wish> wishes;
    /**
     * a List of all news
     */
    @OneToMany(cascade= CascadeType.ALL)
    private List<News> news;
    
    @OneToMany(cascade= CascadeType.ALL)
    private List<TaskCategory> exerciseCategories;
    
    @OneToMany(cascade= CascadeType.ALL)
    private List<ExerciseSheet> exerciseSheets;
    
    @OneToMany(cascade= CascadeType.ALL)
    @LazyCollection(LazyCollectionOption.TRUE)
    private List<MeetingDate> times;
    
    @OneToMany(cascade= CascadeType.ALL)
    private List<DownloadCategory> downloads;
    
    @ElementCollection
    private Map<ExerciseSheet, ScoreData> score;
    
    @ElementCollection
    private Map<ExerciseSheet, HandingInData> handingIns; 
    
    @OneToMany(cascade=CascadeType.ALL)
    private List<Mail> mails;
    
    @OneToMany(cascade=CascadeType.ALL)
    private List<StaticPage> staticPages;
    @Id
    @GeneratedValue
    private Long id;
    
    @OneToMany(cascade= CascadeType.ALL)
    private List<LectureMenuItem> menuItems;
    /**
     * 
     */
    
    @OneToMany(cascade=CascadeType.ALL)
    private List<MenuCategory> categorys;    
    
    public Lecture() {
    }
    
    /**
     * create a new lecture
     * @param name name of the lecture
     */
    public Lecture (String name) {
        this.info = new LectureInformation(name);
        this.exerciseCategories = new ArrayList<TaskCategory>();
        this.exerciseCategories.add(new TaskCategory("Übungsblatt", 100));
        this.times  = new ArrayList<MeetingDate>();
        this.staticPages = new ArrayList<StaticPage>();
        this.wishes = new HashMap<String, Wish>();
        this.news = new ArrayList<News>();
        this.exerciseSheets = new ArrayList<ExerciseSheet>();
        this.downloads = new ArrayList<DownloadCategory>();
        this.score = new HashMap<ExerciseSheet, ScoreData>();
        this.handingIns = new HashMap<ExerciseSheet, HandingInData>();
        this.mails = new ArrayList<Mail>();
        this.categorys = new ArrayList<MenuCategory>();
        
        this.setUpMenuItem();
    }
    
    public File getHandingInFile (String user, ExerciseSheet sheet, HandingIn handingIn) {
        return this.handingIns.get(sheet).getField().get(user).get(handingIn);
    }

    public void addUser(User user) {
        this.info.addUser(user);    
        HibernateUtil.update(user);
    }
    
    /**
     * move a specified news one position down
     * @param n the news which will be moved
     */
    public void moveNewsDown(News n) {
        System.out.println("Move Down called");
        int pos = Math.min(this.news.indexOf(n) + 1, this.news.size()-1);
        this.news.remove(n);
        this.news.add(pos, n);
    }
    
   /**
     * move a specified news one position up
     * @param n the news which will be moved
     */
    public void moveNewsUp(News n) {
        System.out.println("Move Up called");
        int pos = Math.max(this.news.indexOf(n) - 1, 0);
        this.news.remove(n);
        this.news.add(pos, n);
    }

    /**
     * 
     * @return 
     */
    public Collection<Wish> getAllWishes() {
        return this.wishes.values();
    }
    
    /**
     * 
     */
    public void addWish(String username, String[] wish) {
        this.wishes.put(username, new Wish(wish, username));
        HibernateUtil.update(this);
    }
    
    
    public Wish getWish (String username) {
        return this.wishes.get(username);
    }
    
    /**
     * add a news at the first position
     * @param n the new news
     */
    public void addNews(News n) {
        this.news.add(0,n);
        HibernateUtil.update(n);
    }
    
    public void removeTime(MeetingDate m) {
        System.out.println("Time gelöscht");
        this.times.remove(m);
        HibernateUtil.delete(m);
    }
    
    public void createTime() {
        System.out.println("Time erzeugt");
        MeetingDate d = new MeetingDate();
        this.times.add(d);
        HibernateUtil.update(d);
    }
    
    public List<MeetingDate> getTimes() {
        System.out.println("Art von MeetingDate Liste:" + this.times.getClass());
        return new ArrayList<MeetingDate> (this.times);
    }
    
    public List<ExerciseSheet> getExerciseSheets() {
        return exerciseSheets;
    }

    public List<TaskCategory> getExerciseCategories() {
        return exerciseCategories;
    }
    
    public void addExerciseCategories(TaskCategory ec) {
        this.exerciseCategories.add(ec);
        HibernateUtil.update(ec);
    }
    
    public List<News> getNews() {
        return this.news;
    }

    public void addSheet(ExerciseSheet sheet) {        
        this.exerciseSheets.add(sheet);
        this.score.put(sheet, new ScoreData(this.initScoreHashMap(sheet)));
        this.handingIns.put(sheet, new HandingInData (this.initHandingInMap(sheet)));
        HibernateUtil.update(this);
    }
    
    public void addWeeklyDate(MeetingDate time) {
        this.times.add(time);
        HibernateUtil.update(time);
    }


    public List<DownloadCategory> getDownloads() {
        return this.downloads;
    }
    
    public void addDownloadCategory(String dc) {
        this.downloads.add(new DownloadCategory(dc));
        HibernateUtil.update(dc);
    }
    
    public void removeCategory(DownloadCategory dc) {
        this.downloads.remove(dc);
        HibernateUtil.delete(dc);
    }
    
    public void removeNews (News n) {
        this.news.remove(n);
        HibernateUtil.delete(n);
    }
    
    public void createNews() {
        News n = new News("", new Date());
        this.news.add(1,n);
        HibernateUtil.update(n);
    }
    
    public List<Map.Entry<String, List<Score>>> getScoreBySheet(ExerciseSheet sheet) {
        return new ArrayList<Map.Entry<String,List<Score>>>(score.get(sheet).getField().entrySet());                
    }

    public LectureInformation getInfo() {
        return info;
    }

    public void setInfo(LectureInformation info) {
        this.info = info;
        HibernateUtil.update(this);
    }

    private Map<String, Map<HandingIn, File>> initHandingInMap(ExerciseSheet sheet) {
        System.out.println("Initialisiere HandingIn für sheet" + sheet.getName());
        Map<String, Map<HandingIn, File>> map = new HashMap<String, Map<HandingIn, File>>();
        for (User user: this.info.getUsers()) {
             Map<HandingIn, File> handingMap = new HashMap<HandingIn, File>();
             map.put(user.getUsername(), handingMap);
        }
        return map;
    }
    
    public void addHandingIn (ExerciseSheet sheet, String user, HandingIn handingIn, File file) {
        System.out.println("Versuche hinzuzufügen für User " + user);
        System.out.println("Sheet: " + sheet.getName());
        Map<String, Map<HandingIn, File>> stringMap = this.handingIns.get(sheet).getField();
        Map<HandingIn, File> map = stringMap.get(user);
        map.put(handingIn, file);
        HibernateUtil.update(this);
    }
    
    private Map<String, List<Score>> initScoreHashMap(ExerciseSheet sheet) {
        Map<String, List<Score>> map = new HashMap<String, List<Score>>();
        for (User user: this.info.getUsers()) {
            List scores = new ArrayList<Score>();
            for (int i=0;i<sheet.getExercises().size();i++) {
                scores.add(new Score());
            }
            map.put(user.getUsername(),scores);
        }        
        return map;
    }
    
    public List<User> getStudents() {
        List<User> students = new ArrayList<User>();
        for (User u: this.info.getUsers()) {
            if (u.getUserRole(this.getInfo().getName()) == Role.STUDENT) {
                students.add(u);
            }
        }
        return students;
    }
    
    public void addStaticPage(StaticPage s) {        
        this.staticPages.add(s);
        HibernateUtil.update(s);
    }
    
    public void removeStaticPage(StaticPage s) {
        this.staticPages.remove(s);
        HibernateUtil.delete(s);
    }
    
    public List<StaticPage> getStaticPages() {
        return this.staticPages;
    }

    public List<User> getTutors() {
        List<User> user = new ArrayList<User>();
        String lecturename = this.getInfo().getName();
        for (User u: this.info.getUsers()) {
            if (u.getUserRole(lecturename) == Role.TUTOR)
                user.add(u);
        }
        return user;
    }    
    
    public void addMail(Mail m) {
        this.mails.add(m);
        HibernateUtil.update(m);
    }
    
    public void removeSheet(ExerciseSheet sheet) {
        this.exerciseSheets.remove(sheet);
        HibernateUtil.delete(sheet);
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Map<ExerciseSheet, HandingInData> getHandingIns() {
        return handingIns;
    }
    
    private void setUpMenuItem() {
        MenuCategory c = new MenuCategory("Admin");
        this.menuItems = new ArrayList<LectureMenuItem>();
        this.menuItems.add(new LectureMenuItem("Anmelden","account.jsf"));
        LectureMenuItem m = new LectureMenuItem("Veranstaltung konfigurieren","admin.jsf");
        m.getRights().giveViewRights(Role.ADMIN);
        c.addItem(m);
        this.menuItems.add(m);
        m = new LectureMenuItem("Menu bearbeiten","editMenu.jsf");
        m.getRights().giveViewRights(Role.ADMIN);
        c.addItem(m);
        this.menuItems.add(m);
        this.menuItems.add(new LectureMenuItem("User bearbeiten","editUserRole.jsf"));
        
        this.menuItems.add(new LectureMenuItem("Downloads","editDownloads.jsf"));
        
        this.menuItems.add(new LectureMenuItem("Zuteilung zu Übungsgruppen","exerciseGroupAssigning.jsf"));
        this.menuItems.add(new LectureMenuItem("Übungsgruppen bearbeiten","editExerciseGroups.jsf"));
        this.menuItems.add(new LectureMenuItem("Übungsgruppen","viewExerciseGroup.jsf"));
        
        this.menuItems.add(new LectureMenuItem("Statische Seiten","editStaticPages.jsf"));
        
        this.menuItems.add(new LectureMenuItem("News","news.jsf"));
        
        this.menuItems.add(new LectureMenuItem("E-Mail versenden","sendMail.jsf"));
        this.menuItems.add(new LectureMenuItem("E-Mails betrachten","showMails.jsf"));
        
        this.menuItems.add(new LectureMenuItem("Neues Übungsblatt","newSheet.jsf"));
        this.menuItems.add(new LectureMenuItem("Übungsblätter","showSheets.jsf"));        
        
        this.menuItems.add(new LectureMenuItem("Abgaben hochladen","uploadHandingIn.jsf"));
        this.menuItems.add(new LectureMenuItem("Abgaben herunterladen","downloadHandingIns.jsf"));
        
        this.menuItems.add(new LectureMenuItem("Punkte eintragen","tutorEnterScore.jsf"));
        this.menuItems.add(new LectureMenuItem("Punkteübersicht","viewAllScore.jsf"));
        this.menuItems.add(new LectureMenuItem("Alle Punkte eintragen","enterScore.jsf"));
        this.menuItems.add(new LectureMenuItem("Punkte betrachten","viewScore.jsf"));
        this.menuItems.add(new LectureMenuItem("Abgaben Browsen", "browse.jsf"));
        this.menuItems.add(new LectureMenuItem("Abgabe nachreichen", "handInLater.jsf"));
        this.menuItems.add(new LectureMenuItem("Score Groups", "editScoreGroups.jsf"));
        
        m = new LectureMenuItem("Menu Wizard", "menuWizard.jsf");
        m.getRights().giveViewRights(Role.ADMIN);
        c.addItem(m);
        this.menuItems.add(m);
        
        c.getRights().giveViewRights(Role.ADMIN);
        this.getCategorys().add(c);
        
        HibernateUtil.update(this);
    }

    public List<LectureMenuItem> getMenuItems() {
        return menuItems;
    }
    
    public void removeTaskCategory(TaskCategory t) {
        this.exerciseCategories.remove(t);
        HibernateUtil.delete(t);
    }
    
    public void createTaskCategory() {
        TaskCategory t = new TaskCategory();
        this.exerciseCategories.add(t);
        HibernateUtil.update(t);
        
    }

    public Map<ExerciseSheet, ScoreData> getScore() {
        return score;
    }
    
    public List<MenuCategory> getCategorys() {
        return this.categorys;
    }
    
    /**
     * 
     * @param c 
     */
    public void addCategory(MenuCategory c) {
        this.categorys.add(c);
        HibernateUtil.update(c);
    }
    
    public void removeCategory(MenuCategory c) {
        this.categorys.remove(c);
        HibernateUtil.delete(c);
    }
    
    public void createCategory() {
        MenuCategory m = new MenuCategory("");
        this.categorys.add(m);
        HibernateUtil.update(m);
    }

    public void setCategorys(List<MenuCategory> categorys) {
        this.categorys = categorys;
        HibernateUtil.update(this);
    }

    public void setDownloads(List<DownloadCategory> downloads) {
        this.downloads = downloads;
        HibernateUtil.update(this);        
    }

    public void setExerciseCategories(List<TaskCategory> exerciseCategories) {
        this.exerciseCategories = exerciseCategories;
        HibernateUtil.update(this);        
    }

    public void setExerciseSheets(List<ExerciseSheet> exerciseSheets) {
        this.exerciseSheets = exerciseSheets;
        HibernateUtil.update(this);        
    }

    public void setHandingIns(Map<ExerciseSheet, HandingInData> handingIns) {
        this.handingIns = handingIns;
        HibernateUtil.update(this);        
    }

    public void setMails(List<Mail> mails) {
        this.mails = mails;
        HibernateUtil.update(this);        
    }

    public void setMenuItems(List<LectureMenuItem> menuItems) {
        this.menuItems = menuItems;
        HibernateUtil.update(this);        
    }

    public void setNews(List<News> news) {
        this.news = news;
        HibernateUtil.update(this);        
    }

    public void setScore(Map<ExerciseSheet, ScoreData> score) {
        this.score = score;
        HibernateUtil.update(this);        
    }

    public void setStaticPages(List<StaticPage> staticPages) {
        this.staticPages = staticPages;
        HibernateUtil.update(this);        
    }

    public void setTimes(List<MeetingDate> times) {
        this.times = times;
        HibernateUtil.update(this);        
    }

    public void setWishes(HashMap<String, Wish> wishes) {
        this.wishes = wishes;
        HibernateUtil.update(this);        
    }

    public List<Mail> getMails() {
        return mails;
    }

    public HashMap<String, Wish> getWishes() {
        return wishes;
        
    }
}